波瀾壯闊的 rvgc 與 as 篇大致告一段落。今日回到一般的 binutils 工具程式中,目標是:size!
size 工具程式的主要功能就是展示各區段的大小,比方說如果直接將這個程式用在 /bin/ls
身上的話:
$ size /bin/ls
text data bss dec hex filename
122923 4688 4832 132443 2055b /bin/ls
說實在的,看起來實在很沒用。除了這幾個區段之外的區段資訊呢?給了這些大小資訊又能怎麼樣呢?能夠至少提供區段在檔案內的偏移量嗎?
這是預設的 BSD size 輸出模式。結果非預設的 SYSV 輸出模式竟然就有提供上述問題的解答了:
$ size -A /bin/ls
/bin/ls :
section size addr
.interp 28 568
.note.ABI-tag 32 596
.note.gnu.build-id 36 628
.gnu.hash 244 664
.dynsym 3336 912
.dynstr 1524 4248
.gnu.version 278 5772
.gnu.version_r 112 6056
.rela.dyn 7632 6168
.init 23 13800
.plt 16 13824
.plt.got 8 13840
.text 75529 13856
.fini 9 89388
.rodata 19948 89408
.eh_frame_hdr 2140 109356
.eh_frame 12028 111496
.init_array 8 2224144
.fini_array 8 2224152
.data.rel.ro 2616 2224160
.dynamic 464 2226776
.got 976 2227240
.data 616 2228224
.bss 4832 2228864
.comment 26 0
Total 132469
這不是擺明了有用多了嗎!雖然 addr 的量使用十進位,感覺也是很莫名其妙就是了。因此,筆者的實作決定參考後者的格式輸出,然後將 addr 欄位內容改成 16 進位的格式;為求方便轉換,size 欄位的部份輸出 10 進位與 16 進位的格式。
從 readelf 時的程式碼可以參考許多東西,而最主要的元件都已經在那時候展示過了:區段名稱、區段大小、區段在記憶體中的位址、以及區段在檔案中的偏移量。
因為沒有必要針對不同的參數儲存相對應的輸出,所以簡化了內部結構:
type sizeUtil struct {
file *elf.File
raw []byte
}
由於是純粹讀檔就能夠完成的一個工具程式,Init
和 DefineFlags
函數就不需要實作什麼。維持和 readelf 一樣的實作,我們還是在 Run
函式中將所需資訊存成 json 格式,然後在 Output
函式中輸出:
func (siu *sizeUtil) Run(args map[string]interface{}) error {
str := "]"
for _, p := range siu.file.Sections {
raw, err := json.Marshal(p)
if err != nil {
return err
}
str = "," + string(raw) + str
}
re, _ := regexp.Compile("^,")
str = re.ReplaceAllString(str, "[")
siu.raw = []byte(str)
return nil
}
func (siu *sizeUtil) Output(args map[string]interface{}) error {
w := new(tabwriter.Writer)
w.Init(os.Stdout, 0, 8, 2, ' ', tabwriter.AlignRight)
var output []elf.SectionHeader
json.Unmarshal(siu.raw, &output)
fmt.Fprintln(w, "Name\tSize\tAddress\tOffset\t")
for _, s := range output {
fmt.Fprintf(w, "%s\t%d(%x)\t%x\t%x\t\n",
s.Name, s.Size, s.Size, s.Addr, s.Offset)
}
fmt.Fprintln(w)
w.Flush()
}
最後輸出的結果類似這樣:
$ /tmp/size /bin/ls
Name Size Address Offset
.shstrtab 246(f6) 0 20282
.comment 26(1a) 0 20268
.bss 4832(12e0) 220280 20268
.data 616(268) 220000 20000
.got 976(3d0) 21fc28 1fc28
.dynamic 464(1d0) 21fa58 1fa58
.data.rel.ro 2616(a38) 21f020 1f020
.fini_array 8(8) 21f018 1f018
.init_array 8(8) 21f010 1f010
.eh_frame 12028(2efc) 1b388 1b388
.eh_frame_hdr 2140(85c) 1ab2c 1ab2c
.rodata 19948(4dec) 15d40 15d40
.fini 9(9) 15d2c 15d2c
.text 75529(12709) 3620 3620
.plt.got 8(8) 3610 3610
.plt 16(10) 3600 3600
.init 23(17) 35e8 35e8
.rela.dyn 7632(1dd0) 1818 1818
.gnu.version_r 112(70) 17a8 17a8
.gnu.version 278(116) 168c 168c
.dynstr 1524(5f4) 1098 1098
.dynsym 3336(d08) 390 390
.gnu.hash 244(f4) 298 298
.note.gnu.build-id 36(24) 274 274
.note.ABI-tag 32(20) 254 254
.interp 28(1c) 238 238
0(0) 0 0
應該還不錯吧!
的確,相比於系列文開始為止至今,本日的內容的確是稍微單薄了一點。但畢竟筆者也是需要休息的,恰好有幾個小型的工具程式可以充當折衷,也算是喘一口氣吧。明日我們就從 strip 繼續下去吧!